#include <iostream>
#include <mysql/mysql.h>
#include "mysql_management.h"

using namespace std;

thread_local mysql_client mysql_management::client_;

mysql_management::mysql_management() : work_guard_(boost::asio::make_work_guard(io_context_)) {}

void mysql_management::init(int thread_cnt,
                            const std::string host,
                            const std::string user,
                            const std::string password,
                            const std::string database,
                            unsigned short port) {
  host_ = host;
  user_ = user;
  password_ = password;
  database_ = database;
  port_ = port;
  if (mysql_library_init(0, NULL, NULL)) {
    fprintf(stderr, "could not initialize MySQL library\n");
    exit(1);
  }
  for (int i = 0; i < thread_cnt; ++i) {
    threads_.push_back(thread(std::bind(&mysql_management::run, this)));
  }
}

// 线程执行主程序
void mysql_management::run() {
  // 连接数据库
  auto ret = client_.init(host_, user_, password_, database_, port_);
  if (!ret) {
    cout << "mysql_management client_ init failed." << endl;
    return;
  }
  io_context_.run();
  client_.close();
}

// 停止mysql_management
void mysql_management::stop() {
  io_context_.stop();
  for (auto&& th : threads_) {
    th.join();
  }
  mysql_library_end();
}

void mysql_management::select(
  std::string sql,
  boost::asio::io_context& io_context,
  std::function<void(bool is_success, std::vector<std::vector<std::string>> results)> func) {
  boost::asio::post(io_context_, [sql, &io_context, func]() {
    std::cout << "select:" << this_thread::get_id() << endl;
    std::vector<std::vector<std::string>> results;
    bool is_success = client_.select(sql, results);
    io_context.post(std::bind(func, is_success, results));
  });
}

void mysql_management::execute(std::vector<std::string> sqls,
                               boost::asio::io_context& io_context,
                               std::function<void(bool is_success)> func) {
  boost::asio::post(io_context_, [sqls, &io_context, func]() {
    cout << "execute:" << this_thread::get_id() << endl;
    bool is_success = client_.execute(sqls);
    io_context.post(std::bind(func, is_success));
  });
}